/***************************************************************************
 *   ZSocket - library                                                     *
 *                                                                         *
 *   Copyright (C) 2008 by kuerant                                         *
 *                         <kuerant@gmail.com>                             *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This library is distributed in the hope that it will be usefull, but  *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
 *   Library General Public License for more details.                      *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston,                *
 *   MA 02111-1307, USA                                                    *
 ***************************************************************************/

#ifndef ZSOCKET_MICROTIME_HPP
#define ZSOCKET_MICROTIME_HPP

#include    <stdio.h>
#include    <time.h>
#include    <sys/time.h>

namespace   zsocket
{

struct  microtime_t 
{
public  :
    microtime_t() : m_sec(0), m_usec(0) {}
    microtime_t( const struct timeval& rhs ) : m_sec(rhs.tv_sec), m_usec(rhs.tv_usec) {}
    
public  :
    microtime_t&    operator=( int iSeconds )
    {
        if ( iSeconds >= 0 ) {
            this->m_sec = iSeconds;
            this->m_usec = 0;
        }
        
        return  *this;
    }
     
    microtime_t operator-( const microtime_t& rhs )
    {
        microtime_t result;
        
        result.m_usec = this->m_usec - rhs.m_usec;
        if ( result.m_usec < 0 ) {
            result.m_sec = this->m_sec - (rhs.m_sec + 1);
            result.m_usec += 1000000;
        }
        else {
            result.m_sec = this->m_sec - rhs.m_sec;
        }
        
        return  result;
    }
    
    microtime_t operator+( const microtime_t& rhs )
    {
        microtime_t result;
        
        result.m_usec = this->m_usec + rhs.m_usec;
        if ( result.m_usec >= 1000000 ) {
            result.m_sec = this->m_sec + (rhs.m_sec + 1);
            result.m_usec -= 1000000;
        }
        else {
            result.m_sec = this->m_sec + rhs.m_sec;
        }
        
        return  result;
    }
    
    microtime_t&    operator-=( const microtime_t& rhs )
    {
        this->m_usec -= rhs.m_usec;
        if ( this->m_usec < 0 ) {
            this->m_sec -= (rhs.m_sec + 1);
            this->m_usec += 1000000;
        }
        else {
            this->m_sec -= rhs.m_sec;
        }
        
        return  *this;
    }

    microtime_t&    operator+=( const microtime_t& rhs )
    {
        this->m_usec += rhs.m_usec;
        if ( this->m_usec >= 1000000 ) {
            this->m_sec += (rhs.m_sec + 1);
            this->m_usec -= 1000000;
        }
        else {
            this->m_sec += rhs.m_sec;
        }
        
        return  *this;
    }
    
    microtime_t operator-( int iSeconds )
    {
        microtime_t result;
        
        result.m_usec = this->m_usec;
        result.m_sec = this->m_sec - iSeconds;
        
        return  result;
    }

    microtime_t operator+( int iSeconds )
    {
        microtime_t result;
        
        result.m_usec = this->m_usec;
        result.m_sec = this->m_sec + iSeconds;
        
        return  result;
    }
    
    microtime_t&    operator-=( int iSeconds )
    {
        this->m_sec -= iSeconds;
        
        return  *this;
    }
    
    microtime_t&    operator+=( int iSeconds )
    {
        this->m_sec += iSeconds;
        
        return  *this;
    }
    
    bool    operator<( const microtime_t& rhs )
    {
        if (this->m_sec < rhs.m_sec) {
            return    true;
        }
        else if ((this->m_sec == rhs.m_sec) && (this->m_usec < rhs.m_usec)) {
            return    true; 
        }
        
        return    false;
    }

    bool    operator==( const microtime_t& rhs )
    {
        if ((this->m_sec == rhs.m_sec) && (this->m_usec == rhs.m_usec)) {
            return    true; 
        }
        
        return    false;
    }

    bool    operator>( const microtime_t& rhs )
    {
        if (this->m_sec > rhs.m_sec) {
            return    true;
        }
        else if ((this->m_sec == rhs.m_sec) && (this->m_usec > rhs.m_usec)) {
            return    true; 
        }
        
        return    false;
    }

    operator double ()
    {
        double  d = this->m_sec + (this->m_usec / 1000000.0);
        
        return  d;
    }
    
    const char* c_str()
    {
#ifdef  __FreeBSD__
        int iSize = snprintf( m_szBuf, sizeof(m_szBuf) - 1, "%u.%06lu", this->m_sec, this->m_usec );
#else
        int iSize = snprintf( m_szBuf, sizeof(m_szBuf) - 1, "%lu.%06lu", this->m_sec, this->m_usec );
#endif
    
        m_szBuf[ iSize ] = '\0';    
        
        return  m_szBuf;
    }

public  :
    time_t      m_sec;     /* seconds */
    suseconds_t m_usec;    /* microseconds */
    
private :
    char    m_szBuf[ 32 ];
};
typedef struct microtime_t  microtime_t;

microtime_t     microtime( void );

}   // namespace help

#endif  // ZSOCKET_MICROTIME_HPP



